package com.mimo.comet.ws.endpoint;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yeauty.pojo.Session;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.mimo.comet.constants.CometType;
import com.mimo.comet.provider.ISession;

public class WebSocketChannel implements ISession {
  private static final Logger log = LoggerFactory.getLogger(WebSocketChannel.class);

  private final String sessionId;

  private final String terminalType;

  private final Map<String, String> attributes = new HashMap<>();

  @JsonIgnore
  private volatile Session delegate;

  @JsonIgnore
  private volatile boolean closed = false;

  /**
   * 考虑到业务上，最后访问时间的设置，实际上是有一个比较大的容错性的，即不要求精准。也不存在比对或者原子增加的过程，所以，此处不建议使用Atomic相关原子操作类
   */
  private volatile long lastAccessTime;

  public WebSocketChannel(Session delegate, String sessionId, String terminalType) {
    Objects.requireNonNull(delegate);
    Objects.requireNonNull(sessionId);
    Objects.requireNonNull(terminalType);
    this.delegate = delegate;
    this.sessionId = sessionId;
    this.terminalType = terminalType;
    this.lastAccessTime = System.currentTimeMillis();
  }

  public WebSocketChannel(Session delegate, String sessionId, String terminalType, Map<String, String> attributes) {
    this(delegate, sessionId, terminalType);
    Objects.requireNonNull(attributes);
    this.attributes.putAll(attributes);
  }

  /**
   * 统一写出口日志打印
   */
  @Override
  public void write(String data) {
    if (!this.closed) {
      if (Objects.equals(this.getTerminalType(), "WEB")) { // 如果连接进来的是H5页面，则以binary UTF8输出
        delegate.sendBinary(data.getBytes(StandardCharsets.UTF_8));
      } else {
        delegate.sendText(data);
      }
      this.touch();
    } else {
      log.warn("session:[{}] closed and failed send msg:{}", this.sessionId, data);
    }
  }

  @Override
  public long getLastAccessTime() {
    return lastAccessTime;
  }

  @Override
  public void touch() {
    lastAccessTime = System.currentTimeMillis();
  }

  @Override
  public CometType getCometType() {
    return CometType.WebSocket;
  }

  @Override
  public String getSessionId() {
    return sessionId;
  }

  @Override
  public void close() {
    this.closed = true;
    if (Objects.nonNull(delegate)) {
      this.delegate.close();
    }
  }

  @Override
  public Object getDelegate() {
    return delegate;
  }

  @Override
  public void addAttribute(String key, String value) {
    attributes.put(key, value);
  }

  @Override
  public String getAttribute(String key) {
    return attributes.get(key);
  }

  @Override
  public Map<String, String> getAttributeMap() {
    return attributes;
  }

  @Override
  public String removeAttribute(String key) {
    return attributes.remove(key);
  }

  @Override
  public boolean isClosed() {
    return this.closed;
  }

  @Override
  public String getTerminalType() {
    return this.terminalType;
  }

}
